const { ccclass, property } = cc._decorator;

enum RenderType {
    fill = 1,
    stroke = 2
};

enum LineJoin {
    BEVEL = 0,
    MITER = 1,
    ROUND = 2
}
enum LineCap {
    BUTT = 0,
    ROUND = 1,
    SQUARE = 2
}

@ccclass
export default abstract class baseColorShap extends cc.Component {
    protected _readyRender = false;

    protected _graphics: cc.Graphics = null;

    protected _canFill: boolean = true;
    protected _canStroke: boolean = true;

    protected _needLineWidth: boolean = true;
    protected _needLineJoin: boolean = true;
    protected _needLineCap: boolean = true;
    protected _needMiterLimit: boolean = true;

    protected _colorA: number = 0;

    @property
    protected _renderType: RenderType = RenderType.fill;
    @property({
        type: cc.Enum(RenderType),
        tooltip: CC_DEV && '渲染类型\n1、fill: 填充\n2、stroke: 描边',
        visible(this: baseColorShap) {
            return this._canFill && this._canStroke;
        }
    })
    get renderType() {
        if (this._canFill && this._canStroke) {
            return this._renderType;
        } else if (this._canFill) {
            return RenderType.fill;
        } else {
            return RenderType.stroke;
        }
    }
    set renderType(value) {
        this._renderType = value;
        this.updateColorShap();
    }

    /**************************************以下为重写**************************************/
    // 当前线条宽度
    @property
    _lineWidth: number = 2;
    @property({
        tooltip: CC_DEV && '当前线条宽度',
        visible(this: baseColorShap) {
            return this._needLineWidth && this.renderType === RenderType.stroke;
        }
    })
    get lineWidth(): number { return this._lineWidth; }
    set lineWidth(value) {
        this._lineWidth = value;
        this.updateColorShap();
    }

    // 用来设置2个长度不为0的相连部分（线段，圆弧，曲线）如何连接在一起的属性。
    @property
    _lineJoin: LineJoin = LineJoin.BEVEL;
    @property({
        type: cc.Enum(LineJoin),
        tooltip: CC_DEV && '用来设置2个长度不为0的相连部分（线段，圆弧，曲线）如何连接在一起的属性',
        visible(this: baseColorShap) {
            return this._needLineJoin && this.renderType === RenderType.stroke;
        }
    })
    get lineJoin(): LineJoin { return this._lineJoin; }
    set lineJoin(value) {
        this._lineJoin = value;
        this.updateColorShap();
    }

    // 指定如何绘制每一条线段末端。
    @property
    _lineCap: LineCap = LineCap.BUTT;
    @property({
        type: cc.Enum(LineCap),
        tooltip: CC_DEV && '指定如何绘制每一条线段末端',
        visible(this: baseColorShap) {
            return this._needLineCap && this.renderType === RenderType.stroke;
        }
    })
    get lineCap(): LineCap { return this._lineCap; }
    set lineCap(value) {
        this._lineCap = value;
        this.updateColorShap();
    }

    // 设置斜接面限制比例
    @property
    _miterLimit: number = 1;
    @property({
        tooltip: CC_DEV && '设置斜接面限制比例',
        visible(this: baseColorShap) {
            return this._needMiterLimit && this.renderType === RenderType.stroke;
        }
    })
    get miterLimit(): number { return this._miterLimit; }
    set miterLimit(value) {
        this._miterLimit = value;
        this.updateColorShap();
    }

    static RenderType: typeof RenderType = RenderType

    constructor() {
        super();

        this._colorA = 0;

        // 可以fill、可以stroke
        this._canFill = true;
        this._canStroke = true;
        // 需要的参数
        this._needLineWidth = true;
        this._needLineJoin = false;
        this._needLineCap = false;
        this._needMiterLimit = false;
    }


    onLoad() {
        if (this._graphics) return;

        // 添加一个私有节点(私有节点在编辑器中不可见)
        // cc.PrivateNode与cc.Layout组件有冲突，使用cc.Node来替代
        const privateNode = new cc.Node('Graphics');
        privateNode['_localZOrder'] = cc.macro.MIN_ZINDEX << 16;
        if (CC_EDITOR) {
            privateNode["_objFlags"] |= (cc.Object["Flags"].DontSave | cc.Object["Flags"].LockedInEditor | cc.Object["Flags"].HideInHierarchy);
        }
        this._graphics = privateNode.addComponent(cc.Graphics);
        privateNode.active = false;
        this.node.addChild(privateNode);

        this.node.on('color-changed', this.updateColorShap, this);
        this.node.on('size-changed', this.updateColorShap, this);
        this.node.on('anchor-changed', this.updateColorShap, this);
        privateNode.on('position-changed', this.updateColorShap, this);

        this.updateColorShap();
    }

    onDestroy() {
        // 仅仅销毁此组件的清空下，根据清空回收graphics节点
        if (this.node && this.node.isValid) {
            if (!this._graphics || !this._graphics.node || !this._graphics.node.isValid || this._graphics.node.parent !== this.node) return;
            this._graphics.node.destroy();
        }
    }

    onEnable() {
        if (!this._graphics || !this._graphics.node || this._graphics.node.parent !== this.node) return;
        this._graphics.node.active = true;
    }

    onDisable() {
        if (!this._graphics || !this._graphics.node || this._graphics.node.parent !== this.node) return;
        this._graphics.node.active = false;
    }

    canFill() {
        return this._canFill;
    }

    canStroke() {
        return this._canStroke;
    }

    update() {
        if (this._readyRender || this._colorA !== this.node.opacity) {
            this._readyRender = false;
            this.updateColorShap();
        }
    }

    updateColorShap(graphics?: cc.Graphics) {
        graphics = graphics instanceof cc.Graphics ? graphics : this._graphics;

        if (!graphics) {
            return this._readyRender = true;
        }

        this._colorA = this.node.opacity;
        const color = cc.color(this.node.color.r, this.node.color.g, this.node.color.b, this._colorA);

        graphics.lineWidth = this.lineWidth;
        graphics.lineCap = this.lineCap as any;
        graphics.lineJoin = this.lineJoin as any;
        graphics.miterLimit = this.miterLimit;

        graphics.fillColor = color;
        graphics.strokeColor = color;
        graphics.clear();

        const centerX = this.node.width * (0.5 - this.node.anchorX);
        const centerY = this.node.height * (0.5 - this.node.anchorY);
        if (graphics && graphics.node && graphics.node.parent === this.node) {
            const offsetX = -this._graphics.node.x;
            const offsetY = -this._graphics.node.y;
            this.overrideDraw(graphics, centerX + offsetX, centerY + offsetY);
        } else {
            this.overrideDraw(graphics, centerX, centerY);
        }
        this.renderType === RenderType.fill ? graphics.fill() : graphics.stroke();
    }

    /**
     * 需要重写
     */
    protected abstract overrideDraw(cxt: cc.Graphics, centerX: number, centerY: number): void
}
